﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Kinect;
using BicycleTrafficSimulator.DataModel;
using System.Threading;

namespace BicycleTrafficSimulator.DataModel
{
    class KinectController
    {
        private Game game;
        private KinectSensor kinect;
        private Skeleton[] skeletonData;
        private SkeletonFrame skeletonFrame;
        private const float threshold = 0.05f;
        private bool calibrate = false;
        private float offset = 0;
        protected bool signalLeft = false;
        protected bool signalRight = false;
        private bool kinectOn = false;

        public bool KinectOn
        {
            get { return kinectOn; }
            set { kinectOn = value; }
        }

        public KinectController(Game game)
        {
            this.game = game;

        }

        public void Initialize()
        {
            //initialize Kinect
            try
            {
                kinect = KinectSensor.KinectSensors[0];
                kinect.SkeletonStream.Enable();
                kinect.Start();
                KinectOn = true;
                //add an event handler 
                // kinect.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(kinect_SkeletonFrameReady);

            }
            catch (Exception e)
            {
                //Must show Error Dialog!!!!!
                System.Console.WriteLine("Kinect device not detected!");
                KinectOn = false;
            }
        }

        public void Update(GameTime gameTime)
        {
            skeletonFrame = kinect.SkeletonStream.OpenNextFrame(0);
            detectGestures(skeletonFrame, gameTime);
        }

        //method for working with the joints received from the kinects' skeleton tracking
        private void detectGestures(SkeletonFrame skeletonFrame, GameTime gameTime)
        {
            //if (!((KinectSensor)sender).SkeletonStream.IsEnabled)
            //{
            //    return;
            //}
            // using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
            // {
            Skeleton skeleton = null;

            if (skeletonFrame != null)
            {
                skeletonData = new Skeleton[skeletonFrame.SkeletonArrayLength];
                skeletonFrame.CopySkeletonDataTo(skeletonData);
                // Console.WriteLine("skeleton frame " + skeletonFrame.SkeletonArrayLength);
                skeleton = (from s in skeletonData where s.TrackingState == SkeletonTrackingState.Tracked select s).FirstOrDefault();
            }

            if (skeleton != null)
            {
                if (gameTime != null)
                {
                    //exit
                    if ((skeleton.Joints[JointType.HandRight].Position.Y > skeleton.Joints[JointType.Head].Position.Y) && (skeleton.Joints[JointType.HandLeft].Position.Y > skeleton.Joints[JointType.Head].Position.Y))
                    {
                        kinect.Stop();
                        kinect.Dispose();
                        this.game.scene.Exit();
                    }
                    //semnalizare dreapta
                    if (Math.Abs(skeleton.Joints[JointType.HandRight].Position.X - skeleton.Joints[JointType.ShoulderRight].Position.X) > Math.Abs(skeleton.Joints[JointType.Spine].Position.Y - skeleton.Joints[JointType.ShoulderCenter].Position.Y))
                    {
                        if (!signalLeft)
                        {
                            signalLeft = true;
                            SoundEffect soundEffect;
                            soundEffect = this.game.scene.Content.Load<SoundEffect>("signalRight");
                            soundEffect.Play();
                        }
                        System.Console.WriteLine("SIGNAL RIGHT detected");
                    }
                    else
                    {
                        signalLeft = false;
                    }

                    float leftRightRot = 0;
                    float turningSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
                    turningSpeed *= 1.6f * this.game.GameSpeed;

                    //semnalizare stanga
                    if (Math.Abs(skeleton.Joints[JointType.HandLeft].Position.X - skeleton.Joints[JointType.ShoulderLeft].Position.X) > Math.Abs(skeleton.Joints[JointType.Spine].Position.Y - skeleton.Joints[JointType.ShoulderCenter].Position.Y))
                    {
                        if (!signalRight)
                        {
                            signalRight = true;
                            SoundEffect soundEffect;
                            soundEffect = this.game.scene.Content.Load<SoundEffect>("signalLeft");
                            soundEffect.Play();
                        }
                        System.Console.WriteLine("SIGNAL LEFT detected");
                    }
                    else
                    {
                        signalRight = false;
                    }

                    //turn right
                    if ((skeleton.Joints[JointType.HandLeft].Position.X > skeleton.Joints[JointType.HipLeft].Position.X) && (skeleton.Joints[JointType.HandRight].Position.X > skeleton.Joints[JointType.HipRight].Position.X))
                    {
                        //float leftRightRot = 0;

                        //float turningSpeed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 3000.0f;
                        //turningSpeed *= 3.6f * this.game.GameSpeed;


                        //leftRightRot -= turningSpeed;
                        //Quaternion additionalRotR = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), leftRightRot);
                        //this.game.CameraRotation *= additionalRotR;
                        //float moveSpeedR = gameTime.ElapsedGameTime.Milliseconds / 500.0f * this.game.GameSpeed;

                        //Quaternion additionalRotL = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), leftRightRot);
                        //this.game.CameraRotation *= additionalRotL;
                        //float moveSpeedL = gameTime.ElapsedGameTime.Milliseconds / 500.0f * this.game.GameSpeed;

                        //this.game.Bike.Rotation -= (float)gameTime.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.182f);

                        leftRightRot -= turningSpeed;
                        Quaternion additionalRotR = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), leftRightRot);
                        this.game.CameraRotation *= additionalRotR;
                        float moveSpeedR = gameTime.ElapsedGameTime.Milliseconds / 500.0f * this.game.GameSpeed;
                        this.game.Bike.Rotation -= (float)gameTime.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.182f);

                        //DrawModel();

                        // System.Console.WriteLine("TURN Right detected");
                    }

                    //turn left
                    if ((skeleton.Joints[JointType.HandRight].Position.X < skeleton.Joints[JointType.HipRight].Position.X) && (skeleton.Joints[JointType.HandRight].Position.X < skeleton.Joints[JointType.HipRight].Position.X))
                    {

                        //leftRightRot += turningSpeed;
                        //// modelRotation += (float)gameTimeGlobal.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.091f);
                        leftRightRot += turningSpeed;
                        this.game.Bike.Rotation += (float)gameTime.ElapsedGameTime.TotalMilliseconds * MathHelper.ToRadians(0.091f);

                        //DrawModel();

                        // System.Console.WriteLine("TURN Left detected");
                    }


                    Quaternion additionalRotL = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), leftRightRot);
                    this.game.CameraRotation *= additionalRotL;
                    float moveSpeedL = gameTime.ElapsedGameTime.Milliseconds / 500.0f * this.game.GameSpeed;

                    //start & stop
                    if (skeleton.Joints[JointType.HandLeft].Position.Y > skeleton.Joints[JointType.Spine].Position.Y && skeleton.Joints[JointType.HandRight].Position.Y > skeleton.Joints[JointType.Spine].Position.Y)
                    {
                        //Vector3 addVectorU = Vector3.Transform(new Vector3(0, 0, -1), this.game.CameraRotation);
                        //float moveSpeed = gameTime.ElapsedGameTime.Milliseconds / 250.0f * this.game.GameSpeed;
                        ////  if (moveSpeed + this.game.SpeedUpDownValue > 0)
                        //// {
                        ///*  BoundingSphere bikeSphere = new BoundingSphere(bike.Position + (addVectorU * (moveSpeed + speedUpDownValue)), 0.08f);
                        //  if (CheckCollision(bikeSphere) != CollisionType.None)*/
                        //this.game.SpeedUpDownValue += 0.0005f;
                        ////this.game.Bike.Position += (addVectorU * (moveSpeed + this.game.SpeedUpDownValue));
                        //this.game.Bike.Position += addVectorU * moveSpeed;
                        //// }

                        Vector3 addVectorU = Vector3.Transform(new Vector3(0, 0, -1), this.game.CameraRotation);
                        float moveSpeed = gameTime.ElapsedGameTime.Milliseconds / 500.0f * this.game.GameSpeed;
                        //   xwingPosition += addVectorU * moveSpeed;
                        this.game.SpeedUpDownValue += 0.0005f;
                        this.game.Bike.Position += addVectorU * moveSpeed;

                        System.Console.WriteLine("START bicycle detected");

                        if (!calibrate)
                        {
                            offset = skeleton.Joints[JointType.ShoulderCenter].Position.Z - skeleton.Joints[JointType.HipCenter].Position.Z;
                            calibrate = true;
                        }
                    }
                    else
                    {
                        this.game.SpeedUpDownValue = 0.0f;
                        System.Console.WriteLine("STOP bicycle detected");
                    }
                }
                // }
            }
        }

        public void Unload()
        {
            kinect.Dispose();
            kinect.Stop();
        }
    }
}
